home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
gl_util.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
29KB
|
1,371 lines
/*
* $Id: gl_util.c,v 0.91 1994/02/20 00:52:58 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Low level user routines (one level higher than GL primitives) dealing
* with frame buffer switching, mouse, cursor and rubber objects.
*
*/
#if !defined(lint) && defined(F_ID)
char *id_glu = "$Id: gl_util.c,v 0.91 1994/02/20 00:52:58 zhao Pre-Release $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include "gl/gl.h"
#include "gl/device.h"
#include "gluproto.h"
extern void set_current_window(long);
/*****************************************************************
* Before any routine can be used, glu_init() must be called.
* It will in turn call init_cursor and init_overlay to do the
* job
*******************************************************************/
static void init_overlay(void);
void
glu_init(void)
{
static int init;
if (!init)
{
init_cursor();
init_overlay();
init = 1;
}
}
/*****************************************************************
* Simple Mouse routines
* get_mouse(int *x, int *y); -- get mouse position
* set_mouse(int x, int y); -- warp mouse to (x,y)
* set_mouse_bounds() ; -- restrict movement of mouse
* reset_mouse_bounds() ; -- lift the restriction
* get_mouse_r2w(int *, int *);-- get mouse postion relative window
*****************************************************************/
#ifndef GET_MOUSE
#define GET_MOUSE(x,y) (x)= getvaluator(MOUSEX);\
(y)= getvaluator(MOUSEY)
#define SET_MOUSE(x,y,xi,xf,yi,yf) setvaluator(MOUSEX,(x),(xi),(xf));\
setvaluator(MOUSEY,(y),(yi),(yf))
#endif
static int mxi, myi; /* lower bounds */
static int mxf = XMAXSCREEN; /* X upper bounds */
static int myf = YMAXSCREEN; /* Y upper bounds */
/***************************************************************
* Free mouse from any constraints, i.e., allow free movement
* of mouse
***************************************************************/
void
reset_mouse_bounds(void)
{
int x, y;
GET_MOUSE(x, y);
SET_MOUSE(x, y, (mxi = 0), (mxf = getgdesc(GD_XPMAX)),
(myi = 0), (myf = getgdesc(GD_YPMAX)));
}
/* **************************************************************
* return current mouse position, relative to screen
****************************************************************/
void
get_mouse(int *x, int *y)
{
GET_MOUSE(*x, *y);
}
/*************************************************************
* move mouse to a specific location
*************************************************************/
void
set_mouse(int x, int y)
{
SET_MOUSE(x, y, mxi, mxf, myi, myf);
}
/****************************************************************
* set restrictions on mouse
****************************************************************/
void
set_mouse_bounds(int xmin, int ymin, int xmax, int ymax)
{
int x, y;
GET_MOUSE(x, y);
SET_MOUSE(x, y, (mxi = xmin), (mxf = xmax), (myi = ymin), (myf = ymax));
}
/************************************************************
* similar to get_mouse, except coordinates are relative to window
***************************************************************/
void
get_mouse_r2w(int *x, int *y)
{
long xori, yori;
getorigin(&xori, &yori);
get_mouse(x, y);
*x -= xori;
*y -= yori;
}
/**************************************************************
* Simple overlay routines: If hardware overlay is not avaialble,
* PUPDRAW will be used as XOR drawing is not supported on all
* platforms or OSes. The upshot of this is that drawmode(OVERDRAW)
* should not be used, use switch_frame_buffer instead, which
* will do the right thing
**************************************************************/
#define MAX_OVER 2 /* valid values are 2,4,8 */
/* default colors in overlay */
static int overrgb[][3] =
{
{0, 0, 0}, /* none */
{255, 0, 0}, /* red */
{0, 255, 0}, /* green */
{255, 255, 0} /* yellow. blue is too dark */
};
int over_pup_colors; /* global, how many colors we got */
extern int force_pupdraw; /* undocumented */
static long otherfb; /* hardwhere supported non regular FB */
/***************************************************************
* check if overlay exists and in case it doesn't, pupdraw will be
* used
***************************************************************/
static void
init_overlay(void)
{
long over_plane, pup_plane, pup_colors, overlay_colors = 0;
int i;
const char *func = "OverPupInit";
over_plane = getgdesc(GD_BITS_OVER_SNG_CMODE);
M_info(func, "overlay bitplanes=%d", over_plane);
/* force_pupdraw is undocumented */
if (!force_pupdraw && over_plane > 0)
{
/* don't be too greedy, use MAX_OVER even if more are possible */
over_plane = Min(over_plane, MAX_OVER);
overlay(over_plane);
/* let the caller call gconfig */
/* gconfig(); */
over_pup_colors = overlay_colors = 1 << over_plane;
/* install colormap in overlay only, don't mess with pupdraw */
drawmode(OVERDRAW);
for (i = 0; i < overlay_colors; i++)
mapcolor(i, overrgb[i][0], overrgb[i][1], overrgb[i][2]);
drawmode(NORMALDRAW);
}
/* check out pupdraw */
if ((pup_plane = getgdesc(GD_BITS_PUP_SNG_CMODE)) <= 0 && !over_plane)
{
M_err(func, "No Bitplanes for OVER and PUP !!");
exit(1);
}
M_info(func, "pup bitplanes=%d", pup_plane);
pup_colors = (1 << pup_plane);
/* the real harware framebuffer used */
otherfb = (overlay_colors > 1 ? OVERDRAW : PUPDRAW);
if (over_pup_colors == 0)
over_pup_colors = pup_colors;
M_info("InitOverPup", "using %d bitplanes from %s",
(otherfb == PUPDRAW) ? pup_plane : over_plane,
(otherfb == PUPDRAW) ? "Pupdraw" : "Overlay");
}
/***************************************************
* switch the framebuffer to something other than normaldraw
**************************************************/
void
switch_frame_buffer(void)
{
drawmode(otherfb);
reshapeviewport();
#ifdef MDEBUG
M_debug("SwitchFB", "Switching to %s",
(otherfb == PUPDRAW) ? "pupdraw" : "overlay");
#endif
}
/*********************************************************
* put graphics mode in full screen and clear the framebuffer.
* the fullscreen code MUST be sandwitch between
* pushmatrix/popmatrix, this EXTREMELY important otherwise
* the stack is screwed.
***********************************************************/
static void
clear_fullscr(void)
{
pushmatrix();
fullscrn();
cpack(0);
color(0);
clear();
endfullscrn();
popmatrix();
reshapeviewport();
}
/****************************************************
* clear over_pup framebuffer
****************************************************/
extern long win_id;
void
clear_over_pup(void)
{
set_current_window(win_id);
switch_frame_buffer();
clear_fullscr();
drawmode(NORMALDRAW);
}
void
op_mapcolor(int n, int r, int g, int b)
{
switch_frame_buffer();
mapcolor(n, r, g, b);
drawmode(NORMALDRAW);
}
/***************************************************************
* Misc. routines
***************************************************************/
int
double_buffer_capable(void)
{
return (getgdesc(GD_BITS_NORM_DBL_RED) >= 6) &&
(getgdesc(GD_BITS_NORM_DBL_BLUE) >= 4) &&
(getgdesc(GD_BITS_NORM_DBL_CMODE) >= 8);
}
int
sml_capable(void)
{
return (getgdesc(GD_BLEND) && getgdesc(GD_LINESMOOTH_RGB));
}
/*******************************************************************
* Some basic routines that draw simple geometric figures and
* they take x,y,w,h,f as arguments, representing center (x,y)
* and size (w, h). If f is true, then the region is closed, and it
* will be filled.
*
* All routines are responsible for the drawing only. All mapping,
* colors, framebuffer etc are the responsibilities of the caller
******************************************************************{*/
#define MINCODESIZE /* for small code, maybe a little slower */
/* two choices for specifying a vertex: one is to call a function
* or alternatively use a macro. If MINCODESIZE is defined, function
* version will be used
*/
#ifdef MINCODESIZE
static void
vvf(float x, float y)
{
float xy[2];
xy[0] = x;
xy[1] = y;
v2f(xy);
}
#else
#define vvf(x, y) \
do { float xy[2]; \
xy[0] = (x); \
xy[1] = (y); \
v2f(x,y); \
} while (ZERO)
#endif
/**** draw a strightline from (xi, yi) to (xf, yf) ****/
void
draw_line(float xi, float yi, float xf, float yf)
{
bgnline();
vvf(xi, yi);
vvf(xf, yf);
endline();
}
#define Bfill(f) (f ? bgnpolygon: bgnclosedline)()
#define Efill(f) (f ? endpolygon: endclosedline)()
/* ARGSUSED */
void
gl_line(int x, int y, int w, int h, int f, int a)
{
pushmatrix();
translate(x, y, 0);
rotate(a, 'z');
scale((float) w, (float) h, 1.0);
draw_line(-0.5, 0.0, 0.5, 0.0);
popmatrix();
}
/**************** square, rectangle ********************/
void
gl_rect(int x, int y, int w, int h, int fill, int a)
{
pushmatrix();
translate(x, y, 0);
rotate(a, 'z');
scale((float) w, (float) h, 1.0);
(fill ? rectf : rect) (-0.5, -0.5, 0.5, 0.5);
popmatrix();
}
/************* circle, eliipse ************/
/* ARGSUSED */
void
gl_circ(int x, int y, int w, int h, int fill, int a)
{
pushmatrix();
translate(x, y, 0);
rotate(a, 'z');
scale((float) w, (float) h, 1);
(fill ? circf : circ) (0, 0, 0.5);
popmatrix();
}
/************** draw a star ****************/
#include <math.h>
void
gl_star(int x, int y, int w, int h, int f, int a)
{
static int first = 1;
static float xy[10][2];
int i;
/* generate the unit star on the fly first time */
if (first)
{ /* calculate coordinates */
float t;
float a2r = (acos(-1.0) / 180.0);
float l = (sin(18.0 * a2r) / sin(54.0 * a2r));
first = 0;
for (i = 0, t = 54.0; i < 10; i += 2, t += 72.0)
{
xy[i][0] = l * cos(t * a2r);
xy[i][1] = l * sin(t * a2r);
}
for (i = 1, t = 90.0; i < 10; i += 2, t += 72.0)
{
xy[i][0] = cos(t * a2r);
xy[i][1] = sin(t * a2r);
}
}
/* drw it */
pushmatrix();
translate(x, y, 0);
rotate(a, 'z');
scale(0.5 * w, 0.5 * h, 1.0);
Bfill(f);
for (i = 0; i < 10; i++)
v2f(xy[i]);
Efill(f);
popmatrix();
}
/***************** an arrow. *******************/
void
gl_arrow(int x, int y, int w, int h, int f, int a)
{
float aw = 0.1, al = 0.7; /* arrow width and length */
pushmatrix();
translate(x, y, 0);
rotate(a, 'z');
scale(0.5 * w, 0.5 * h, 1.0);
draw_line(-1.0, 0.0, al, 0.0);
Bfill(f);
vvf(al, aw);
vvf(al, -aw);
vvf(1.0, 0.0);
Efill(f);
popmatrix();
}
/*********** triangle, nabla ***********/
void
gl_tri(int x, int y, int w, int h, int fill, int a)
{
pushmatrix();
translate(x, y, 0);
scale((float) w, (float) h, 1);
rotate(a, 'z');
Bfill(fill);
vvf(0.5, -0.5);
vvf(0, 0.5);
vvf(-0.5, -0.5);
Efill(fill);
popmatrix();
}
/* ARGSUSED */
static void
draw_cross(int x, int y, int w, int h, int fill, int a)
{
draw_line(x - w * 0.5, y - h * 0.5, x + w * 0.5, y + h * 0.5);
draw_line(x - w * 0.5, y + h * 0.5, x + w * 0.5, y - h * 0.5);
}
/*************** cross, times **********/
/* ARGSUSED */
void
gl_plus(int x, int y, int w, int h, int fill, int a)
{
pushmatrix();
translate(x, y, 0);
scale(0.5 * w, 0.5 * h, 1.0);
rotate(a, 'z');
draw_line(0.0, -1.0, 0.0, 1.0);
draw_line(-1.0, 0.0, 1.0, 0.0);
popmatrix();
}
/***** |----| ********************/
/* ARGSUSED */
void
gl_hdist(int x, int y, int w, int h, int fill, int a)
{
pushmatrix();
translate(x, y, 0);
rotate(a, 'z');
scale((float) w, (float) h, 1.0);
draw_line(-0.5, 0, 0.5, 0);
draw_line(-0.5, -0.12, -0.5, 0.12);
draw_line(0.5, -0.12, 0.5, 0.12);
popmatrix();
}
/* End of simple geometric figure routines } */
/**************************************************************
* Routines that deal with rubber objects
* winget and winget are reduced to a minimum and calling
* routine probably should take care some of them
***************************************************************/
/***********************************************************
* Basic drawing routines: void (*draw) (int, int, int, int);
***********************************************************/
typedef void (*Drawobj) (int, int, int, int);
/***** draw a circle at (x,y) with radius = w/2; ****/
static void
rb_circ(int x, int y, int w, int h)
{
int radius = Min(w, h) / 2;
circi(x + radius, y + radius, radius);
}
/**********
draw line from (x,y) to (x+w-1, y+h-1) and mark origin with a circle
*/
static void
rb_line(int x, int y, int w, int h)
{
long v1[2], v2[2];
v1[0] = x;
v1[1] = y;
v2[0] = x + w - 1;
v2[1] = y + h - 1;
bgnline();
v2i(v1);
v2i(v2);
endline();
circi(x, y, 10);
}
/***** draw a rectangle ****/
static void
rb_rect(int x, int y, int w, int h)
{
recti(x, y, x + w - 1, y + h - 1);
}
static int lastx, lasty, lastw, lasth, lastcr;
static int check, xmin, ymin, width, height, onscrn, lastc;
static long lastwin;
static int center, obj;
/**********************************************************
* make sure the object stays within bounds
* width and height are given highier priority than localtions
*********************************************************/
static void
check_rect_bounds(int *x, int *y, int *w, int *h)
{
if (*w < 0)
{
*w = -*w;
*x -= *w;
}
if (*h < 0)
{
*h = -*h;
*y -= *h;
}
if (*w > width)
*w = width;
if (*h > height)
*h = height;
if (*x < xmin)
*x = xmin;
if (*y < ymin)
*y = ymin;
if (*x + *w > xmin + width)
*x = xmin + width - *w;
if (*y + *h > ymin + height)
*y = ymin + height - *h;
}
static void
check_circ_bounds(int *x, int *y, int *w, int *h)
{
int maxdia = Min(width, height);
if (*w < 0)
{
*w = -*w;
*x -= *w;
}
if (*h < 0)
{
*h = -*h;
*y -= *h;
}
if (*w > maxdia)
*w = maxdia;
*h = *w;
if (*x < xmin)
*x = xmin;
if (*y < ymin)
*y = ymin;
if (*x + *w > xmin + width)
*x = xmin + width - *w;
if (*y + *h > ymin + height)
*y = ymin + height - *h;
}
/* width and height can be nagative for lines */
static void
check_line_bounds(int *x, int *y, int *w, int *h)
{
if (Abs(*w) > width)
*w = (*w / Abs(*w)) * width;
if (Abs(*h) > height)
*h = (*h / Abs(*h)) * height;
if (*x < xmin)
*x = xmin;
if (*x > xmin + width)
*x = xmin + width;
if (*x + *w < xmin)
*x = xmin - *w;
if (*x + *w > xmin + width)
*x = xmin + width - *w;
if (*y < ymin)
*y = ymin;
if (*y > ymin + height)
*y = ymin + height;
if (*y + *h < ymin)
*y = ymin - *h;
if (*y + *h > ymin + height)
*y = ymin + height - *h;
}
/***********************************************
* All rubber objects must have XX_new, XX_hide
************************************************/
/* set the rubber color */
static void
rb_color(int c)
{
switch_frame_buffer();
c %= over_pup_colors;
color((lastc = c));
drawmode(NORMALDRAW);
}
/* put up a new rubber. All coordinates are assumed to be ok */
static void
rb_new(int x, int y, int w, int h, Drawobj drawit)
{
int q = (obj == RB_LINE) ? 1 : 2; /* interior size */
switch_frame_buffer();
reshapeviewport();
color(lastc);
if (lastcr > 0)
{
draw_cross(x, y, lastcr, lastcr, 0, 0);
draw_cross(x + w - 1, y + h - 1, lastcr, lastcr, 0, 0);
}
lastx = x;
lasty = y;
lastw = w;
lasth = h;
drawit(x, y, w, h);
drawmode(NORMALDRAW);
onscrn = 1;
/*
* show interior size of the rectangle. In case of line, there is no
* interior size to talk about. Reports theta
*/
show_rect_all(x, y, w - q, h - q, q == 1);
return;
}
/* erase last rubber */
static void
rb_hide(Drawobj drawit)
{
if (!onscrn)
return;
switch_frame_buffer();
reshapeviewport();
color(0);
if (lastcr > 0)
{
draw_cross(lastx, lasty, lastcr, lastcr, 0, 0);
draw_cross(lastx + lastw - 1, lasty + lasth - 1,
lastcr, lastcr, 0, 0);
}
drawit(lastx, lasty, lastw, lasth);
drawmode(NORMALDRAW);
onscrn = 0;
return;
}
/*****************************************************
* Now some high level user routines
****************************************************/
#include "forms.h" /* for qtest etc */
typedef void (*Ckbounds) (int *, int *, int *, int *);
typedef struct
{
int obj;
Drawobj drawit;
Ckbounds checkb;
}
Draw;
static Draw drawobj[] =
{
{RB_RECT, rb_rect, check_rect_bounds},
{RB_CIRC, rb_circ, check_circ_bounds},
{RB_LINE, rb_line, check_line_bounds}
};
static Draw *p = drawobj;
static int maxobjs = sizeof(drawobj) / sizeof(Draw);
/* if set, rubber will center at (x,y) */
void
set_rubber_center(int ctr)
{
center = ctr;
}
/* if there is any rubber on screen */
int
rubber_on_screen(long *win, int *c)
{
*win = lastwin;
*c = lastc;
return onscrn;
}
/* set the rubber bounds. ck==0 disables checking */
void
set_rubber_bounds(int ck, int x, int y, int w, int h)
{
if ((check = ck))
{
width = w;
height = h;
xmin = x;
ymin = y;
}
}
/* which rubber obj to draw */
void
set_rubber_obj(int o)
{
int i = 0;
rb_hide(p->drawit);
for (i = 0; i < maxobjs && drawobj[i].obj != o; i++)
;
if (i < maxobjs)
{
obj = o;
p = &drawobj[obj];
}
/* rb_new(lastx, lasty, lastw, lasth, p->drawit); */
}
int
get_max_rubber_obj(void)
{
return sizeof(drawobj) / sizeof(Draw);
}
/* draw a new one */
/* move a rubber to the new location */
void
rubber_moveto(int *x, int *y, int *w, int *h)
{
long owin = winget();
set_current_window(lastwin);
if (check)
p->checkb(x, y, w, h);
if (!onscrn || *x - lastx || *y - lasty || *w - lastw || *h - lasth)
{
rb_hide(p->drawit);
rb_new(*x, *y, *w, *h, p->drawit);
}
if (owin > 0)
set_current_window(owin);
}
void
rubber_new(long win, int x, int y, int w, int h, int c)
{
set_current_window(lastwin = win);
rb_color(c);
rb_new(x, y, w, h, p->drawit);
}
void
rubber_show(int c)
{
rb_color(c);
rb_new(lastx, lasty, lastw, lasth, p->drawit);
}
void
rubber_hide(void)
{
rb_hide(p->drawit);
}
void
rubber_finish(void)
{
rb_hide(p->drawit);
hide_rect_all();
}
/************************************************************
* Show a rubber object that moves with the mouse.
* this routine returns whenever there is change in the postion
* or when there is Q-event pending
*
* Note: size of the rubber object is NOT changeable, to do that
* Use rubber_info
*/
long
rubber_cursor(long win, short *val, int *x, int *y, int w, int h, int c)
{
long xori, yori, dev = 0;
int moved;
static int lastmx, lastmy;
int mx, my;
set_current_window(lastwin = win);
p = &drawobj[obj];
rb_color(c);
lastcr = 0;
getorigin(&xori, &yori);
moved = 0;
(void) fl_check_forms();
do
{
get_mouse(&mx, &my);
/* we must let this run thru once */
if (lastmx != mx || lastmy != my)
{
lastmx = mx;
lastmy = my;
moved = 1;
*x = (mx - xori);
*y = (my - yori);
if (center)
{
*x -= w / 2;
*y -= h / 2;
}
rubber_moveto(x, y, &w, &h);
}
if (!fl_qtest())
fl_check_forms();
else
dev = fl_qread(val);
}
while ((dev == 0 || *val == 0) && !moved);
return dev;
}
/***********************************************************
* General rectangle routine:
* Both size and location can be changed by mouse or
* keyboard key i,j,k,l.
************************************************************/
static int step = 1;
void
set_rubber_change_rate(int a)
{
if (a > 0)
{
step = a;
show_rect_speed(a);
}
}
static int
in_rect(int x, int y, int xi, int yi, int xsize, int ysize)
{
return (Abs(xi - x) < xsize && Abs(yi - y) < ysize);
}
/***************************************************************
* Handles ijkl, xXyY keys and numbers: return 1 if unknown
*
* if lastcr == 0, the size will not be changable
****************************************************************/
static int
handle_keybd(int k, int *x, int *y, int *w, int *h)
{
int ret = 0, l;
int xm, ym, dist1, dist2;
get_mouse(&xm, &ym);
dist1 = Abs((xm - *x)) + Abs(ym - *y);
dist2 = Abs(xm - (*x + *w - 1)) + Abs(ym - (*y + *h - 1));
l = dist1 < dist2;
switch (k)
{
case 'h':
case 'H':
if (!lastcr || control_down)
{
(*x) -= step;
}
else if (getbutton(RIGHTSHIFTKEY))
{
(*w) -= step;
}
else if (getbutton(LEFTSHIFTKEY))
{
(*x) -= step;
(*w) += step;
}
else if (l)
{
(*x) -= step;
(*w) += step;
}
else
(*w) -= step;
break;
case 'j':
case 'J':
if (!lastcr || control_down)
{
(*y) -= step;
}
else if (getbutton(RIGHTSHIFTKEY))
{
(*h) -= step;
}
else if (getbutton(LEFTSHIFTKEY))
{
(*y) -= step;
(*h) += step;
}
else if (l)
{
(*y) -= step;
(*h) += step;
}
else
(*h) -= step;
break;
case 'l':
case 'L':
if (!lastcr || control_down)
{
(*x) += step;
}
else if (getbutton(RIGHTSHIFTKEY))
{
(*w) += step;
}
else if (getbutton(LEFTSHIFTKEY))
{
(*x) += step;
(*w) -= step;
}
else if (l)
{
(*x) += step;
(*w) -= step;
}
else
(*w) += step;
break;
case 'k':
case 'K':
if (!lastcr || control_down)
{
(*y) += step;
}
else if (getbutton(RIGHTSHIFTKEY))
{
(*h) += step;
}
else if (getbutton(LEFTSHIFTKEY))
{
(*y) += step;
(*h) -= step;
}
else if (l)
{
(*y) += step;
(*h) -= step;
}
else
(*h) += step;
break;
case 'x':
if (lastcr)
{
*w -= 2 * step;
*x += step;
}
break;
case 'X':
if (lastcr)
{
*w += 2 * step;
*x -= step;
}
break;
case 'y':
if (lastcr)
{
*h -= 2 * step;
*y += step;
}
break;
case 'Y':
if (lastcr)
{
*h += 2 * step;
*y -= step;
}
break;
default:
if (k > '0' && k <= '9')
{
set_rubber_change_rate((k - '0'));
}
else
ret = 1;
break;
}
return ret;
}
static void (*ricb) (int, int, int, int);
void
set_rubber_info_cb(void (*fn) (int, int, int, int))
{
ricb = fn;
}
static int
handle_mouse(long dev, int *x, int *y, int *w, int *h,
int xo, int yo, int cr)
{
int ret = 0;
int xm, ym, oxm, oym = -1;
int dx, dy;
int ox = *x, oy = *y;
WHERE_R2W(xm, ym, xo, yo);
if (cr == 0)
{
if (in_rect(xm, ym, *x + *w / 2, *y + *h / 2, *w / 2, *h / 2))
{
if (ricb)
rubber_hide();
do
{
oxm = xm;
oym = ym;
WHERE_R2W(xm, ym, xo, yo);
*x += xm - oxm;
*y += ym - oym;
if (ricb)
{
ricb(ox, oy, *x, *y);
ox = *x;
oy = *y;
}
else
rubber_moveto(x, y, w, h);
}
while (getbutton(dev));
rubber_moveto(x, y, w, h);
return (ox != *x || oy != *y);
}
return 1;
}
if (control_down)
{
do
{
oxm = xm;
oym = ym;
WHERE_R2W(xm, ym, xo, yo);
*x += xm - oxm;
*y += ym - oym;
rubber_moveto(x, y, w, h);
}
while (control_down && mouse_down);
}
else if (in_rect(xm, ym, *x, *y, cr, cr))
{
do
{
WHERE_R2W(xm, ym, xo, yo);
*w -= (dx = (xm - *x + 1));
*h -= (dy = (ym - *y + 1));
*x += dx;
*y += dy;
rubber_moveto(x, y, w, h);
}
while (mouse_down);
}
else if (in_rect(xm, ym, *x + *w - 1, *y + *h - 1, cr, cr))
{
do
{
WHERE_R2W(xm, ym, xo, yo);
*w = xm - *x + 1;
*h = ym - *y + 1;
rubber_moveto(x, y, w, h);
}
while (mouse_down);
}
else
ret = 1;
return ret;
}
static void
event_wait(long win, int xo, int yo, int x, int y, int w, int h, int cr)
{
int xm, ym, in;
do
{
fl_check_forms();
WHERE_R2W(xm, ym, xo, yo);
if (cr != 0)
{
in = in_rect(xm, ym, x, y, cr, cr) ||
in_rect(xm, ym, x + w - 1, y + h - 1, cr, cr);
}
else
{
in = in_rect(xm, ym, x + w / 2, y + h / 2, w / 2, h / 2);
}
set_cursor(win, in ? CUR_HAND : CUR_DEFAULT);
}
while (!fl_qtest());
}
/*
* The ultimate rubber object. both size and location of the rubber
* object can be changed either by mouse or keyboard. All Q events
* are rembered and returned.
*/
long
rubber_info(long win, short *val, int *x, int *y, int *w, int *h,
int fc, int cr)
{
int done = 0, ock = check;
long dev, xo, yo;
p = &drawobj[obj];
set_current_window(lastwin = win);
reshapeviewport();
getorigin(&xo, &yo);
rb_color(fc);
if (lastcr != cr)
{
lastcr = cr;
rb_new(*x, *y, *w, *h, p->drawit);
}
else
{
rubber_moveto(x, y, w, h);
}
check = 0; /* must suspend bound checking */
set_rubber_change_rate(step);
/*
* LeftMouse and MiddleMouse will be dropped unless it does not happen on
* the cross. Loop terminates if others events are present
*/
do
{
event_wait(win, xo, yo, *x, *y, *w, *h, cr);
switch ((dev = fl_qread(val)))
{
case LEFTARROWKEY:
if (*val)
handle_keybd('h', x, y, w, h);
break;
case RIGHTARROWKEY:
if (*val)
handle_keybd('l', x, y, w, h);
break;
case UPARROWKEY:
if (*val)
handle_keybd('k', x, y, w, h);
break;
case DOWNARROWKEY:
if (*val)
handle_keybd('j', x, y, w, h);
break;
case KEYBD:
done = (*val && handle_keybd(*val, x, y, w, h));
break;
case INPUTCHANGE:
if (*val > 0)
set_current_window(*val);
break;
case LEFTMOUSE:
case MIDDLEMOUSE:
done = *val && handle_mouse(dev, x, y, w, h, xo, yo, cr);
break;
default:
done = 1;
break;
}
if (ock)
p->checkb(x, y, w, h);
rubber_moveto(x, y, w, h);
}
while (!done);
if ((check = ock))
p->checkb(x, y, w, h);
set_cursor(win, CUR_DEFAULT);
return dev;
}
void
end_rubber_info(void)
{
fl_qenter(KEYBD, 20);
}
/**********************************************************************
* Color Wheel
******************************************************************{***/
static float cw_fr[200], cw_fg[200], cw_fb[200];
static unsigned long cw_col[200];
static float cw_xy[200][2], cw_ctr[2];
static int nm, cw_max = 255;
#include <math.h>
#ifndef M_PI
#define M_PI cos(-1.0)
#endif
static void
cw_color_scale(void)
{
static int lcw_max = -1;
if (cw_max != lcw_max)
{
int i, r, g, b;
for (i = 0; i < nm; i++)
{
r = cw_fr[i] * cw_max + 0.1;
g = cw_fg[i] * cw_max + 0.1;
b = cw_fb[i] * cw_max + 0.1;
cw_col[i] = r | (g << 8) | (b << 16);
}
lcw_max = cw_max;
}
}
static float
f_theta(double t)
{
if (t < 0.0)
t += 360.0;
if (t <= 60.0)
return 1;
else if (t > 60.0 && t <= 120.0)
return (120 - t) / 60;
else if (t > 120 && t <= 240)
return 0;
if (t > 240. && t <= 300.0)
return (t - 240.0) / 60;
else
return 1;
}
static void
gen_unit_cw(void)
{
int i;
double t, dt = 2.0;
double d2r = M_PI / 180.0;
if (nm != 0)
return;
/* center coordinates */
cw_ctr[0] = cw_ctr[1] = 0;
for (i = 0, t = 0.0; t <= 360.0; t += dt, i++)
{
cw_xy[i][0] = cos(t * d2r);
cw_xy[i][1] = sin(t * d2r);
cw_fr[i] = f_theta(t);
cw_fg[i] = f_theta(t - 120.0);
cw_fb[i] = f_theta((t - 240.0));
}
nm = i;
}
void
draw_color_wheel(int x, int y, int w, int h)
{
int i;
gen_unit_cw();
cw_color_scale();
pushmatrix();
translate(x, y, 0);
scale(w, h, 1);
shademodel(GOURAUD);
bgntmesh();
cpack(cw_max | (cw_max << 8) | (cw_max << 16));
v2f(cw_ctr);
for (i = 0; i < nm; i++)
{
cpack(cw_col[i]);
v2f(cw_xy[i]);
swaptmesh();
}
endtmesh();
popmatrix();
}
void
set_color_wheel_max(int c)
{
cw_max = c;
}
/*** END of Color Wheels *****/